home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright 1990 University of Wisconsin-Madison
- *
- * Permission to use, copy, modify, distribute, and sell this software and its
- * documentation for any purpose is hereby granted without fee, provided that
- * the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the University of Wisconsin-Madison not
- * be used in advertising or publicity pertaining to distribution of the
- * software without specific, written prior permission. The University of
- * Wisconsin-Madison makes no representations about the suitability of this
- * software for any purpose. It is provided "as is" without express or
- * implied warranty.
- *
- * THE UNIVERSITY OF WISCONSIN-MADISON DISCLAIMS ALL WARRANTIES WITH REGARD TO
- * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF WISCONSIN-MADISON BE LIABLE FOR
- * ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Author: Tim Theisen Department of Computer Sciences
- * tim@cs.wisc.edu University of Wisconsin-Madison
- * uwvax!tim 1210 West Dayton Street
- * (608)262-0438 Madison, WI 53706
- */
-
- #include <stdio.h>
- #include <signal.h>
- #include <X11/Xos.h>
-
- #include <X11/Intrinsic.h>
- #include <X11/StringDefs.h>
- #include <X11/Shell.h>
- #include <X11/Xatom.h>
-
- #include <X11/Xaw/AsciiText.h>
- #include <X11/Xaw/Cardinals.h>
- #include <X11/Xaw/Command.h>
- #include <X11/Xaw/Form.h>
- #include <X11/Xaw/Label.h>
- #include <X11/Xmu/Atoms.h>
-
- #include "patchlevel.h"
-
- #ifdef SIGNALRETURNSINT
- #define SIGVAL int
- #else
- #define SIGVAL void
- #endif
-
- /* Respawning is only necessary for X11R4. */
- /* For X11R5, xwalld is run in the Xsetup script. */
- #ifndef XlibSpecificationRelease
- #define RESPAWN
- #endif
-
- typedef struct _AppResources {
- int openDelay;
- int pingInterval;
- int pingTimeout;
- Boolean bell, daemon, notify, raise;
- } AppResources;
-
- AppResources app_resources = {15, 5, 5, True, True, True, True};
-
- static XtResource resources[] = {
- {"openDelay", "OpenDelay", XtRInt, sizeof(int),
- XtOffsetOf(AppResources, openDelay), XtRImmediate, (XtPointer)15},
- {"pingInterval", "PingInterval", XtRInt, sizeof(int),
- XtOffsetOf(AppResources, pingInterval), XtRImmediate, (XtPointer)5},
- {"pingTimeout", "PingTimeout", XtRInt, sizeof(int),
- XtOffsetOf(AppResources, pingTimeout), XtRImmediate, (XtPointer)5},
- {"bell", "Bell", XtRBoolean, sizeof(Boolean),
- XtOffsetOf(AppResources, bell), XtRImmediate, (XtPointer)True},
- {"daemon", "Daemon", XtRBoolean, sizeof(Boolean),
- XtOffsetOf(AppResources, daemon), XtRImmediate, (XtPointer)True},
- {"notify", "Notify", XtRBoolean, sizeof(Boolean),
- XtOffsetOf(AppResources, notify), XtRImmediate, (XtPointer)True},
- {"raise", "Raise", XtRBoolean, sizeof(Boolean),
- XtOffsetOf(AppResources, raise), XtRImmediate, (XtPointer)True},
- };
-
- static XrmOptionDescRec options[] = {
- {"-bell", ".bell", XrmoptionNoArg, (caddr_t)"on"},
- {"-nobell", ".bell", XrmoptionNoArg, (caddr_t)"off"},
- {"-daemon", ".daemon", XrmoptionNoArg, (caddr_t)"on"},
- {"-nodaemon", ".daemon", XrmoptionNoArg, (caddr_t)"off"},
- {"-notify", ".notify", XrmoptionNoArg, (caddr_t)"on"},
- {"-nonotify", ".notify", XrmoptionNoArg, (caddr_t)"off"},
- {"-raise", ".raise", XrmoptionNoArg, (caddr_t)"on"},
- {"-noraise", ".raise", XrmoptionNoArg, (caddr_t)"off"},
- };
-
- static void Deiconified();
- static void Iconified();
- static void delete_window();
-
- static XtActionsRec actions[] = {
- {"Deiconified", Deiconified},
- {"Iconified", Iconified},
- {"Delete", delete_window},
- };
-
- String fallback_resources[] = {
- # include "Xwall.ad.h"
- NULL};
-
- static void Syntax();
- static void make_wall_popup();
- extern char *malloc();
- static SIGVAL catchALRM();
-
- #ifdef RESPAWN
- static String *saved_argv;
- static int saved_argc;
- static SIGVAL catchHUP();
- static int catchXError();
- static int catchXIOError();
- static void catchXtError();
- static void respawn();
- static int connected;
- #endif
-
- XtAppContext app_con;
- static Display *dpy;
- static XtIntervalId timer_id;
- static void pingDisplay();
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- Widget toplevel;
- #ifdef RESPAWN
- int i;
- XErrorHandler oldXError;
- XIOErrorHandler oldXIOError;
-
- saved_argc = argc;
- saved_argv = (String *) malloc((saved_argc + 1) * sizeof(String));
- if (saved_argv == NULL) {
- fprintf(stderr, "%s: Malloc failure!\n, argv[0]");
- exit(1);
- }
- for (i = 0 ; i < saved_argc ; i++) saved_argv[i] = argv[i];
- saved_argv[i] = NULL; /* NULL terminate that sucker. */
-
- /* make ourselves fairly bullet proof */
- (void) signal(SIGHUP, catchHUP);
- oldXError = XSetErrorHandler (catchXError);
- oldXIOError = XSetIOErrorHandler (catchXIOError);
- XtSetErrorHandler (catchXtError);
-
- /* If we are root, Become daemon right away. */
- /* (Don't want to hold up /etc/rc.) */
- if (getuid() == 0) {
- BecomeOrphan();
- BecomeDaemon();
- /* If starting from rc wait for */
- sleep(app_resources.openDelay); /* xdm to get the X server ready */
- }
-
- /* Use root Xauthority file. Automatically refreshed upon display reset */
- setuid(0);
- (void) setenv("XAUTHORITY", "/.Xauthority", True);
- #endif
-
- XtToolkitInitialize();
- app_con = XtCreateApplicationContext();
- XtAppAddActions(app_con, actions, XtNumber(actions));
- XtAppSetFallbackResources(app_con, fallback_resources);
- (void) signal (SIGALRM, catchALRM);
- (void) alarm (app_resources.pingTimeout*60);
- dpy = XtOpenDisplay(app_con, NULL, NULL, "Xwall",
- options, XtNumber(options), &argc, argv);
- (void) alarm(0);
- #ifdef RESPAWN
- if (dpy == NULL) respawn();
- connected = 1;
- #else
- if (dpy == NULL) exit(1);
- #endif
- toplevel = XtAppCreateShell(NULL, "Xwall", applicationShellWidgetClass,
- dpy, NULL, ZERO);
-
- if (argc != 1)
- Syntax(argv[0]);
-
- XtGetApplicationResources(toplevel, (XtPointer) &app_resources,
- resources, XtNumber(resources), NULL, ZERO);
-
- if (app_resources.daemon) {
- BecomeOrphan();
- BecomeDaemon();
- }
-
- /* Ping the display if it is remote */
- if (*DisplayString(dpy) != ':') {
- timer_id = XtAppAddTimeOut(app_con, app_resources.pingInterval*60*1000,
- pingDisplay, (XtPointer) 0);
- }
- make_wall_popup(toplevel);
- XtAppMainLoop(app_con);
- }
-
- static void
- Syntax(call)
- char *call;
- {
- XtDestroyApplicationContext(app_con);
- fprintf(stderr, "Usage: %s\n", call);
- fprintf(stderr, " [-display <display>]\n");
- fprintf(stderr, " [-[no]bell] [-[no]notify] [-[no]raise]\n");
- exit(1);
- }
-
- static void
- pingDisplay(data, id)
- XtPointer data;
- XtIntervalId *id;
- {
- (void) alarm (app_resources.pingTimeout*60);
- XSync(dpy, 0);
- (void) alarm(0);
- timer_id = XtAppAddTimeOut(app_con, app_resources.pingInterval*60*1000,
- pingDisplay, (XtPointer) 0);
- }
-
- #ifdef RESPAWN
- static SIGVAL
- catchALRM()
- {
- respawn();
- }
- static SIGVAL
- catchHUP()
- {
- respawn();
- }
- static int
- catchXError(dpy, xev)
- Display *dpy;
- XErrorEvent *xev;
- {
- connected = 1;
- respawn();
- }
- static int
- catchXIOError(dpy)
- Display *dpy;
- {
- connected = 1;
- respawn();
- }
- static void
- catchXtError(msg)
- String msg;
- {
- connected = 1;
- respawn();
- }
- static void
- respawn()
- {
- if (!connected) /* If we were not connected */
- sleep(app_resources.pingInterval*60);
-
- /* Restart ourself */
- execvp(saved_argv[0], saved_argv);
- }
- #else
- static SIGVAL
- catchALRM()
- {
- exit(1);
- }
- #endif
-
- #define LINES 10
-
- static Time GetTime();
- static void LoseSelection();
- static Boolean RefuseSelection();
- static void LoseManager();
- static void InsertMessage();
- static void dismiss();
- static void Notify();
-
- static Atom message, manager;
- static Atom wm_delete_window; /* Atom sent to destroy a window */
- static Boolean notified;
- static Boolean iconified;
- static Widget wall, form, title, text, button;
- static int message_length;
- static XawTextBlock message_block;
-
- static void
- make_wall_popup(parent)
- Widget parent;
- {
- XFontStruct *font;
- Dimension bottomMargin, leftMargin, rightMargin, topMargin;
- Dimension width, height;
- Arg args[9];
-
- wm_delete_window = XInternAtom(XtDisplay(parent), "WM_DELETE_WINDOW",
- False);
- wall = XtCreatePopupShell("wall", topLevelShellWidgetClass,
- parent, NULL, ZERO);
- form = XtCreateManagedWidget("form", formWidgetClass,
- wall, NULL, ZERO);
- XtSetArg(args[0], XtNfromVert, NULL);
- XtSetArg(args[1], XtNresize, False);
- XtSetArg(args[2], XtNborderWidth, 0);
- XtSetArg(args[3], XtNtop, XtChainTop);
- XtSetArg(args[4], XtNbottom, XtChainTop);
- XtSetArg(args[5], XtNleft, XtChainLeft);
- XtSetArg(args[6], XtNright, XtChainRight);
- title = XtCreateManagedWidget("title", labelWidgetClass,
- form, args, SEVEN);
- XtSetArg(args[0], XtNfromVert, title);
- XtSetArg(args[1], XtNscrollHorizontal, XawtextScrollWhenNeeded);
- XtSetArg(args[2], XtNscrollVertical, XawtextScrollWhenNeeded);
- XtSetArg(args[3], XtNdisplayCaret, False);
- XtSetArg(args[4], XtNdisplayNonprinting, False);
- XtSetArg(args[5], XtNtop, XtChainTop);
- XtSetArg(args[6], XtNbottom, XtChainBottom);
- XtSetArg(args[7], XtNleft, XtChainLeft);
- XtSetArg(args[8], XtNright, XtChainRight);
- text = XtCreateManagedWidget("message", asciiTextWidgetClass,
- form, args, NINE);
- XtSetArg(args[0], XtNfromVert, text);
- XtSetArg(args[1], XtNresize, False);
- XtSetArg(args[2], XtNtop, XtChainBottom);
- XtSetArg(args[3], XtNbottom, XtChainBottom);
- XtSetArg(args[4], XtNleft, XtChainLeft);
- XtSetArg(args[5], XtNright, XtChainRight);
- button = XtCreateManagedWidget("button", commandWidgetClass,
- form, args, SIX);
- XtAddCallback(button, XtNcallback, dismiss, NULL);
-
- XtInstallAccelerators(wall, button);
-
- XtSetArg(args[0], XtNfont, &font);
- XtSetArg(args[1], XtNbottomMargin, &bottomMargin);
- XtSetArg(args[2], XtNleftMargin, &leftMargin);
- XtSetArg(args[3], XtNrightMargin, &rightMargin);
- XtSetArg(args[4], XtNtopMargin, &topMargin);
- XtGetValues(text, args, FIVE);
-
- width = font->max_bounds.width * 80 + leftMargin + rightMargin;
- height = (font->ascent + font->descent) * LINES + topMargin + bottomMargin;
-
- XtSetArg(args[0], XtNwidth, width);
- XtSetArg(args[1], XtNheight, height);
- XtSetValues(title, args, ONE);
- XtSetValues(text, args, TWO);
- XtSetValues(button, args, ONE);
-
- XtRealizeWidget(wall);
- XSetWMProtocols(XtDisplay(wall), XtWindow(wall), &wm_delete_window, 1);
-
- manager = XInternAtom(XtDisplay(text), "MESSAGE_MANAGER", False);
- while (!XtOwnSelection(text, manager, GetTime(wall),
- RefuseSelection, LoseManager, NULL)) {}
- message = XInternAtom(XtDisplay(text), "MESSAGE", False);
- while (!XtOwnSelection(text, message, GetTime(wall),
- RefuseSelection, LoseSelection, NULL)) {}
- }
-
- static Time
- GetTime(w)
- Widget w;
- {
- XSetWindowAttributes attributes;
- static Window myw;
- Time now = 0;
- XEvent event;
- Display *dpy = XtDisplay(w);
-
- /* Create an unmapped window, that the window manager will ignore.
- * This invisble window will be used to do a zero lenght property
- * append. The event returned furnishes the timestamp */
-
- if (!myw) {
- attributes.override_redirect = True;
- attributes.event_mask = PropertyChangeMask;
- myw = XCreateWindow(dpy, DefaultRootWindow(dpy), 0, 0, 1, 1, 0,
- CopyFromParent, CopyFromParent, CopyFromParent,
- CWOverrideRedirect|CWEventMask, &attributes);
- }
-
- XChangeProperty(dpy, myw, XA_NULL(dpy), XA_NULL(dpy), 8,
- PropModeAppend, NULL, 0);
-
- while (now == 0) {
- XtAppNextEvent(app_con, &event);
- if ((event.type == PropertyNotify) && (event.xproperty.window == myw) &&
- (event.xproperty.atom == XA_NULL(dpy)))
- now = event.xproperty.time;
- else
- XtDispatchEvent(&event);
- }
-
- return(now);
- }
-
- static void
- LoseSelection(w, selection)
- Widget w;
- Atom *selection;
- {
- XtGetSelectionValue(w, *selection, XA_STRING, InsertMessage,
- NULL, GetTime(w));
- }
-
- /*ARGSUSED*/
- static Boolean
- RefuseSelection(w, selection, target, type, value, length, format)
- Widget w;
- Atom *selection, *target, *type;
- XtPointer *value;
- unsigned long *length;
- int *format;
- {
- return False;
- }
-
- /*ARGSUSED*/
- static void
- LoseManager(w, selection)
- Widget w;
- Atom *selection;
- {
- XtDestroyApplicationContext(app_con);
- exit(0);
- }
-
- static void
- InsertMessage(w, client_data, selection, type, value, length, format)
- Widget w;
- XtPointer client_data;
- Atom *selection, *type;
- XtPointer value;
- unsigned long *length;
- int *format;
- {
- Arg args[2];
-
- if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0) {
- while (!XtOwnSelection(w, message, GetTime(w),
- RefuseSelection, LoseSelection, NULL)) {}
- return;
- }
-
- message_block.firstPos = 0;
- message_block.length = *length;
- message_block.ptr = value;
- message_block.format = FMT8BIT;
-
- XawTextDisableRedisplay(text);
-
- XtSetArg(args[0], XtNeditType, XawtextAppend);
- XtSetValues(text, args, ONE);
- XawTextReplace(text, message_length, message_length, &message_block);
- message_length = message_length + message_block.length;
-
- XtSetArg(args[0], XtNeditType, XawtextRead);
- XtSetArg(args[1], XtNinsertPosition, message_length);
- XtSetValues(text, args, TWO);
- XawTextEnableRedisplay(text);
- XtPopup(wall, XtGrabNone);
- if (app_resources.raise) XMapRaised(XtDisplay(wall), XtWindow(wall));
- if (app_resources.bell) XBell(XtDisplay(wall), 0);
- if (app_resources.notify) Notify();
-
- while (!XtOwnSelection(w, message, GetTime(w),
- RefuseSelection, LoseSelection, NULL)) {}
-
- XtFree(value);
- }
-
- static void
- dismiss(w, client_data, call_data)
- Widget w;
- XtPointer call_data, client_data;
- {
- Arg args[2];
-
- XtPopdown(wall);
- XtSetArg(args[0], XtNeditType, XawtextEdit);
- XtSetArg(args[1], XtNinsertPosition, 0);
- XtSetValues(text, args, TWO);
- message_block.length = 0;
- XawTextReplace(text, 0, message_length, &message_block);
- XtSetArg(args[0], XtNeditType, XawtextRead);
- XtSetValues(text, args, ONE);
- message_length = 0;
-
- }
-
- /* Implement WM_DELETE_WINDOW protocol */
- static void
- delete_window(w, event, params, num_params)
- Widget w;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- if (event->type == ClientMessage &&
- event->xclient.data.l[0] != wm_delete_window) return;
- dismiss(w, (XtPointer)NULL, (XtPointer)NULL);
- }
-
- static void
- Notify ()
- {
- Arg arglist[1];
- char *oldName;
- char *newName;
-
- if (!iconified || !app_resources.notify || notified)
- return;
- XtSetArg (arglist[0], XtNiconName, &oldName);
- XtGetValues (wall, arglist, 1);
- newName = malloc (strlen (oldName) + 3);
- if (!newName)
- return;
- sprintf (newName, "%s *", oldName);
- XtSetArg (arglist[0], XtNiconName, newName);
- XtSetValues (wall, arglist, 1);
- free (newName);
- notified = True;
- }
-
- /*ARGSUSED*/
- static void
- Deiconified (widget, event, params, num_params)
- Widget widget;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- Arg arglist[1];
- char *oldName;
- char *newName;
- int oldlen;
-
- iconified = False;
- if (!app_resources.notify || !notified)
- return;
- XtSetArg (arglist[0], XtNiconName, &oldName);
- XtGetValues (wall, arglist, 1);
- oldlen = strlen (oldName);
- if (oldlen >= 2) {
- newName = malloc (oldlen - 1);
- if (!newName)
- return;
- strncpy (newName, oldName, oldlen - 2);
- newName[oldlen - 2] = '\0';
- XtSetArg (arglist[0], XtNiconName, newName);
- XtSetValues (wall, arglist, 1);
- free (newName);
- }
- notified = False;
- }
-
- /*ARGSUSED*/
- static void
- Iconified (widget, event, params, num_params)
- Widget widget;
- XEvent *event;
- String *params;
- Cardinal *num_params;
- {
- iconified = True;
- }
-